package com.cicadalane.androlate;

/*
 * Copyright (C) 2011 cicada.software@gmail.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.DocumentFragment;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

public class XmlUtils {

	public static List<Element> getChildrenByTagName(Element parent, String name) {
		return XmlUtils.getChildrenByTagName(parent, new String[] { name });
	}

	public static List<Element> getChildrenByTagName(Element parent,
			String[] names) {
		List<Element> nodeList = new ArrayList<Element>();
		for (Node child = parent.getFirstChild(); child != null; child = child
				.getNextSibling()) {
			if (child.getNodeType() == Node.ELEMENT_NODE) {
				for (String name : names) {
					if (name.equals(child.getNodeName())) {
						nodeList.add((Element) child);
						break;
					}
				}
			}
		}
		return nodeList;
	}

	public static Element getFirstChildByTagName(Element parent, String name) {
		List<Element> list = XmlUtils.getChildrenByTagName(parent,
				new String[] { name });
		if (list.size() > 0)
			return list.get(0);
		else
			return null;
	}

	public static String getInnerXml(Node node)
			throws ParserConfigurationException,
			TransformerFactoryConfigurationError, TransformerException {
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < node.getChildNodes().getLength(); i++)
			sb.append(getOuterXml(node.getChildNodes().item(i)));
		return sb.toString();
	}

	public static String getOuterXml(Node n)
			throws ParserConfigurationException,
			TransformerFactoryConfigurationError, TransformerException {
		Transformer xformer = TransformerFactory.newInstance().newTransformer();
		xformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
		// initialize StreamResult with File object to save to file
		StreamResult result = new StreamResult(new StringWriter());
		DOMSource source = new DOMSource(n);
		xformer.transform(source, result);
		String xmlString = result.getWriter().toString();
		return xmlString;
	}

	public static DocumentFragment parseFragment(Document doc, String xml)
			throws SAXException, IOException, ParserConfigurationException {
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		DocumentFragment fragment = doc.createDocumentFragment();
		String wellformedxml = "<__parseFragment__>" + xml
				+ "</__parseFragment__>";
		Document fragmentdoc = dbf.newDocumentBuilder().parse(
				new InputSource(new StringReader(wellformedxml)));

		Node node = doc.importNode(fragmentdoc.getDocumentElement(), true);

		while (node.hasChildNodes()) {
			fragment.appendChild(node.removeChild(node.getFirstChild()));
		}

		return fragment;
	}

	public static void removeAllChildren(Node node) {
		while (node.hasChildNodes()) {
			node.removeChild(node.getFirstChild());
		}
	}

	public static void setInnerXml(Node node, String xml) throws SAXException,
			IOException, ParserConfigurationException {
		DocumentFragment fragment;
		fragment = XmlUtils.parseFragment(node.getOwnerDocument(), xml);
		XmlUtils.removeAllChildren(node);
		node.appendChild(fragment);
		return;
	}

	/*
	 * save a XML Document to a file
	 */
	public static void writeXmlFile(Document doc, String filename)
			throws TransformerConfigurationException, TransformerException,
			IOException {
		writeXmlFile(doc, filename, true);
	}

	public static void writeXmlFile(Document doc, String filename,
			boolean indent) throws TransformerConfigurationException,
			TransformerException, IOException {

		Source source = new DOMSource(doc);

		FileOutputStream outputStream = new FileOutputStream(filename);
		Result result = new StreamResult(new OutputStreamWriter(outputStream,
				"UTF8"));

		doc.setXmlStandalone(true);
		// Write the DOM document to the file
		TransformerFactory factory = TransformerFactory.newInstance();
		factory.setAttribute("indent-number", 4);

		Transformer xformer = factory.newTransformer();
		xformer.setOutputProperty(OutputKeys.INDENT, "yes");
		xformer.setOutputProperty(OutputKeys.METHOD, "xml");
		xformer.setOutputProperty(OutputKeys.ENCODING, "UTF8");
		xformer.transform(source, result);
	}
}
